package com.ilxqx.framework.system.util;

import com.google.common.collect.Lists;
import com.ilxqx.framework.system.form.SearchForm;
import com.ilxqx.framework.system.form.search.annotation.Condition;
import com.ilxqx.framework.system.strategy.search.ConditionStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.List;

/**
 * 搜索条件构建工具类
 * @author venus
 */
@Slf4j
public final class SearchPredicateUtils {

    /**
     * 根据搜索表单，动态构件查询查询条件
     * @param searchForm 搜索表单对象
     * @param root 域对象根对象
     * @param builder 构建器
     * @param <T> 搜索表单对象泛型
     * @param <E> 域对象泛型
     * @return 条件断言List
     */
    @NonNull
    public static <T extends SearchForm, E> List<Predicate> buildPredicates(@NonNull T searchForm, Root<E> root, CriteriaBuilder builder) {
        Field[] fields = searchForm.getClass().getDeclaredFields();
        List<Predicate> predicateList = Lists.newArrayListWithCapacity(20);
        for (Field field : fields) {
            // 忽略没有Condition注解的字段
            if (!field.isAnnotationPresent(Condition.class)) {
                continue;
            }

            Condition condition = field.getDeclaredAnnotation(Condition.class);

            // 获取字段的值
            Object value = ReflectionUtils.getFieldValue(field, searchForm);

            if (value == null) {
                // 如果字段值为NULL，那就跳过
                continue;
            }

            Path path = root.get(field.getName());
            if (path == null) {
                // 找不到实体中的字段，跳过
                continue;
            }

            ConditionStrategy conditionStrategy = ReflectionUtils.newInstance(condition.conditionStrategy());
            // 获取相应的处理策略
            if (conditionStrategy == null) {
                // 忽略本字段的处理
                continue;
            }
            Predicate predicate = conditionStrategy.handle(value, path, builder);
            if (predicate == null) {
                // 类型无法做条件构建，跳过
                continue;
            }
            predicateList.add(predicate);
        }
        // 返回构建的条件
        return predicateList;
    }

}
